﻿Option Strict On

Imports System.Collections.ObjectModel
Imports System.Data
Imports System.Collections
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Globalization

Namespace FTP
    ''' <summary>
    ''' Ftp item list.
    ''' </summary>
    Public Class FtpItemCollection
        Implements IEnumerable(Of FtpItem)
        Private _list As New List(Of FtpItem)()

        Private _totalSize As Long

        Private Shared COL_NAME As String = "Name"
        Private Shared COL_MODIFIED As String = "Modified"
        Private Shared COL_SIZE As String = "Size"
        Private Shared COL_SYMBOLIC_LINK As String = "SymbolicLink"
        Private Shared COL_TYPE As String = "Type"
        Private Shared COL_ATTRIBUTES As String = "Attributes"
        Private Shared COL_RAW_TEXT As String = "RawText"

        ''' <summary>
        ''' Default constructor for FtpItemCollection.
        ''' </summary>
        Public Sub New()
        End Sub

        ''' <summary>
        ''' Split a multi-line file list text response and add the parsed items to the collection.
        ''' </summary>
        ''' <param name="path">Path to the item on the FTP server.</param>
        ''' <param name="fileList">The multi-line file list text from the FTP server.</param>
        ''' <param name="itemParser">Line item parser object used to parse each line of fileList data.</param>
        Public Sub New(ByVal path As String, ByVal fileList As String, ByVal itemParser As IFtpItemParser)
            Parse(path, fileList, itemParser)
        End Sub

        ''' <summary>
        ''' Merges two FtpItemCollection together into a single collection.
        ''' </summary>
        ''' <param name="items">Collection to merge with.</param>
        Public Sub Merge(ByVal items As FtpItemCollection)
            If items Is Nothing Then
                Throw New ArgumentNullException("items", "must have a value")
            End If

            For Each item As FtpItem In items
                Dim newItem As New FtpItem(item.Name, item.Modified, item.Size, item.SymbolicLink, item.Attributes, item.ItemType, _
                 item.RawText)
                newItem.ParentPath = item.ParentPath
                Me.Add(newItem)
            Next
        End Sub

        Private Sub Parse(ByVal path As String, ByVal fileList As String, ByVal itemParser As IFtpItemParser)
            Dim lines As String() = SplitFileList(fileList)

            Dim length As Integer = lines.Length - 1
            For i As Integer = 0 To length
                Dim item As FtpItem = itemParser.ParseLine(lines(i))
                If item IsNot Nothing AndAlso (item.Name <> "." And item.Name <> "..") Then
                    ' set the parent path to the value passed in
                    item.ParentPath = path
                    _list.Add(item)
                    _totalSize += item.Size
                End If
            Next
        End Sub

        Private Function SplitFileList(ByVal response As String) As String()
            Dim crlfSplit As Char() = New Char(1) {ControlChars.Cr, ControlChars.Lf}
            Return response.Split(crlfSplit, StringSplitOptions.RemoveEmptyEntries)
        End Function

        ''' <summary>
        ''' Convert current FtpCollection to a DataTable object.
        ''' </summary>
        ''' <return>Data table object.</return>
        Public Function ToDataTable() As DataTable
            Dim dataTbl As New DataTable()
            Try
                dataTbl.Locale = CultureInfo.InvariantCulture

                CreateColumns(dataTbl)

                For Each item As FtpItem In _list
                    Dim row As DataRow = dataTbl.NewRow()
                    row(COL_NAME) = item.Name
                    row(COL_MODIFIED) = item.Modified
                    row(COL_SIZE) = item.Size
                    row(COL_SYMBOLIC_LINK) = item.SymbolicLink
                    row(COL_TYPE) = item.ItemType.ToString()
                    row(COL_ATTRIBUTES) = item.Attributes
                    row(COL_RAW_TEXT) = item.RawText
                    dataTbl.Rows.Add(row)
                Next

                Return dataTbl
            Catch
                Return Nothing
            Finally
                dataTbl.Dispose()
            End Try
        End Function

        Private Sub CreateColumns(ByVal dataTbl As DataTable)
            dataTbl.Columns.Add(New DataColumn(COL_NAME, GetType(String)))
            dataTbl.Columns.Add(New DataColumn(COL_MODIFIED, GetType(DateTime)))
            dataTbl.Columns.Add(New DataColumn(COL_SIZE, GetType(Long)))
            dataTbl.Columns.Add(New DataColumn(COL_TYPE, GetType(String)))
            dataTbl.Columns.Add(New DataColumn(COL_ATTRIBUTES, GetType(String)))
            dataTbl.Columns.Add(New DataColumn(COL_SYMBOLIC_LINK, GetType(String)))
            dataTbl.Columns.Add(New DataColumn(COL_RAW_TEXT, GetType(String)))
        End Sub

        ''' <summary>
        ''' Gets the size, in bytes, of all files in the collection as reported by the FTP server.
        ''' </summary>
        Public ReadOnly Property TotalSize() As Long
            Get
                Return _totalSize
            End Get
        End Property

        ''' <summary>
        ''' Searches for the specified object and return the zero-based index of the
        ''' first occurrence within the entire FtpItemCollection list.
        ''' </summary>
        ''' <param name="item">The FtpItem to locate in the collection.</param>
        ''' <return>The zero-based index of the first occurrence of item within the entire if found; otherwise, -1.</return>
        Public Function IndexOf(ByVal item As FtpItem) As Integer
            Return _list.IndexOf(item)
        End Function

        ''' <summary>
        ''' Adds an FtpItem to the end of the FtpItemCollection list.
        ''' </summary>
        ''' <param name="item">FtpItem object to add.</param>
        Public Sub Add(ByVal item As FtpItem)
            _list.Add(item)
        End Sub

        ''' <summary>
        '''  Gets the number of elements actually contained in the FtpItemCollection list.
        ''' </summary>
        Public ReadOnly Property Count() As Integer
            Get
                Return _list.Count
            End Get
        End Property

        Private Function GetEnumerator() As IEnumerator(Of FtpItem) Implements IEnumerable(Of FTP.FtpItem).GetEnumerator
            Return _list.GetEnumerator()
        End Function

        Public Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
            Return _list.GetEnumerator()
        End Function

        ''' <summary>
        ''' Gets an FtpItem from the FtpItemCollection based on index value.
        ''' </summary>
        ''' <param name="index">Numeric index of item to retrieve.</param>
        ''' <return>FtpItem</return>
        Default Public ReadOnly Property Item(ByVal index As Integer) As FtpItem
            Get
                Return _list(index)
            End Get
        End Property

        ''' <summary>
        ''' Searches for the specified object based on the 'name' parameter value
        ''' and return true if an object with the name is found; otherwise false.
        ''' </summary>
        ''' <param name="name">The name of the FtpItem to locate in the collection.</param>
        ''' <return>True if the name if found; otherwise false.</return>
        Public Function ContainsName(ByVal name As String) As Boolean
            If name Is Nothing Then
                Throw New ArgumentNullException("name", "must have a value")
            End If

            For Each item As FtpItem In _list
                If name = item.Name Then
                    Return True
                End If
            Next

            Return False
        End Function
    End Class
End Namespace